package com.syni.mdd.yhd.common.all.controller.pay.wxPay;

import com.alibaba.fastjson.JSON;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.syni.mdd.yhd.common.all.config.pay.wxPay.WxPayBean;
import com.syni.mdd.yhd.common.all.config.pay.wxPay.WxPayBeanFactory;
import com.syni.mdd.yhd.common.all.constants.Constants;
import com.syni.mdd.yhd.common.all.constants.ResultCode;
import com.syni.mdd.yhd.common.all.controller.pay.aliPay.AliPayController;
import com.syni.mdd.yhd.common.all.entity.BmsDxOrder;
import com.syni.mdd.yhd.common.all.service.BmsDxOrderService;
import com.syni.mdd.yhd.common.all.service.BmsPortOrderLogService;
import com.syni.mdd.yhd.common.all.service.pay.aiPay.AliPayService;
import com.syni.mdd.yhd.common.all.service.pay.wxPay.WxPayService;
import com.syni.mdd.yhd.common.all.utils.RequestParamUtils;
import com.syni.mdd.sjb.common.component.utils.common.utils.ParamsMap;
import com.syni.mdd.sjb.common.component.utils.common.utils.ResultMapHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>IJPay 让支付触手可及，封装了微信支付、支付宝支付、银联支付常用的支付方式以及各种常用的接口。</p>
 *
 * <p>不依赖任何第三方 mvc 框架，仅仅作为工具使用简单快速完成支付模块的开发，可轻松嵌入到任何系统里。 </p>
 *
 * <p>IJPay 交流群: 723992875</p>
 *
 * <p>Node.js 版: https://gitee.com/javen205/TNW</p>
 *
 * <p>微信支付 Demo</p>
 *
 * @author Javen
 */
@RestController
@RequestMapping("/wxPay")
public class WxPayController extends AbstractWxPayApiController {
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    BmsDxOrderService bmsDxOrderService;

    @Autowired
    WxPayService wxPayService;

    @Autowired
    AliPayService aliPayService;

    @Autowired
    BmsPortOrderLogService bmsPortOrderLogService;

    @Autowired
    AliPayController aliPayController;

    //回調url
    private static String notifyUrl;
    private static String refundNotifyUrl;
    private static final String USER_PAYING = "USERPAYING";


    @Override
    public WxPayApiConfig getApiConfig(String channel) {
        WxPayApiConfig apiConfig;
        WxPayBean wxPayBean = WxPayBeanFactory.getProperties(channel);
        try {
            apiConfig = WxPayApiConfigKit.getApiConfig(wxPayBean.getAppId());
        } catch (Exception e) {
            apiConfig = WxPayApiConfig.builder()
                    .appId(wxPayBean.getAppId())
                    .mchId(wxPayBean.getMchId())
                    .partnerKey(wxPayBean.getPartnerKey())
                    .certPath(wxPayBean.getCertPath())
                    .domain(wxPayBean.getDomain())
                    .build();
            WxPayApiConfigKit.putApiConfig(apiConfig);
        }
        notifyUrl = apiConfig.getDomain().concat("/wxPay/payNotify");
        refundNotifyUrl = apiConfig.getDomain().concat("/wxPay/refundNotify");
        return apiConfig;
    }

    //@GetMapping("/getKey")
    //@ResponseBody
    /*public String getKey() {
        return WxPayApi.getSignKey(wxPayBean.getMchId(), wxPayBean.getPartnerKey(), SignType.MD5);
    }*/

    /**
     * 微信小程序支付demo
     */
    /*@PostMapping(value = "/miniAppPay")
    @ResponseBody
    @CheckParams(checkAuth = true,params = {"orderId","orderNo","openId"})
    public Map<String,Object> miniAppPay(@RequestBody ParamsMap paramsMap) {
        //需要通过授权来获取openId
        String openId = paramsMap.getString("openId");
        Integer orderId = Integer.parseInt(paramsMap.get("orderId").toString());
        String orderNo = paramsMap.get("orderNo").toString();
        //检验订单号和订单id是否一致
        Optional<BmsDxOrder> bmsDxOrderOptional = bmsDxOrderService.getBaseDao().findById(orderId);
        if(!bmsDxOrderOptional.isPresent()){
            return ResultMapHelper.result(ResultCode.CODE_ORDER_NO_EXIST, ResultMsg.CODE_ORDER_NO_EXIST);
        }
        BmsDxOrder bmsDxOrder = bmsDxOrderOptional.get();
        if(!bmsDxOrder.getOrderNo().equals(orderNo)){
            return ResultMapHelper.result(ResultCode.CODE_ORDER_ID_NOMATCH_NO, ResultMsg.CODE_ORDER_ID_NOMATCH_NO);
        }
        Map<String,Object> checkMap = bmsDxOrderService.checkOrderCanPay(bmsDxOrder);
        if(!ResultCode.CODE_NORMAL.equals(checkMap.get("status").toString())){
            return checkMap;
        }

        String ip = IpKit.getRealIp(RequestParamUtils.getRequest());
        if (StrKit.isBlank(ip)) {
            ip = "127.0.0.1";
        }
        WxPayApiConfig wxPayApiConfig = getApiConfig(WxPayBeanFactory.MIN_APP_CHANNEL);

        Double totalAmt = bmsDxOrder.getActualConsum();

        Double wxPayTotal = ArithUtil.round(ArithUtil.mul(totalAmt,100),0);
        String wxPayFree = String.valueOf(wxPayTotal.intValue());
        //wxPayFree = "10";
        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(wxPayApiConfig.getAppId())
                .mch_id(wxPayApiConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .body(aliPayService.getOrderSubject(bmsDxOrder))
                .attach(aliPayService.getOrderSubject(bmsDxOrder))
                .out_trade_no(bmsDxOrder.getOrderNo())
                .total_fee(wxPayFree)
                .spbill_create_ip(ip)
                .notify_url(notifyUrl)
                .trade_type(TradeType.JSAPI.getTradeType())
                .openid(openId)
                .build()
                .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);

        String xmlResult = WxPayApi.pushOrder(false, params);

        log.info(xmlResult);
        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
        // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
        String returnCode = result.get("return_code");
        String returnMsg = result.get("return_msg");
        String err_codes_des = result.get("err_codes_des");
        if (!(WxPayKit.codeIsOk(returnCode) && "SUCCESS".equals(result.get("result_code")))) {
            return ResultMapHelper.result(ResultCode.CODE_ERROR_100,err_codes_des);
        }
        String prepayId = result.get("prepay_id");
        Map<String, String> packageParams = WxPayKit.miniAppPrepayIdCreateSign(wxPayApiConfig.getAppId(), prepayId,
                wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
        String jsonStr = JSON.toJSONString(packageParams);
        log.info("小程序支付的参数:" + jsonStr);
        Map<String,Object> resultMap = new HashMap<>();
        //resultMap.put("prepayId",prepayId);
        resultMap.putAll(packageParams);
        return ResultMapHelper.success(resultMap,ResultMsg.MSG_GET_SUCCESS);
    }*/


    /**
     * 公众号支付
     */
    /*@PostMapping(value = "/webPay")
    @ResponseBody
    public Map<String,Object> webPay(@RequestBody ParamsMap paramsMap) {
        // openId，采用 网页授权获取 access_token API：SnsAccessTokenApi获取
        String openId = paramsMap.getString("openId");
        String orderId = paramsMap.getString("orderId");
        String orderType = paramsMap.getString("orderType");
        Map<String,Object> retMap = bmsPortOrderLogService.getPortBusOrder(openId,orderId,orderType);
        if(!(retMap.containsKey("status") && ResultCode.CODE_NORMAL.equals(retMap.get("status")))){
            return ResultMapHelper.result(ResultCode.CODE_ERROR_100,ResultMsg.HAND_FAIL);
        }
        Map<String,Object> data = (Map<String, Object>) retMap.get("data");
        List<OrderRpcDto> orderRpcDtos = (List<OrderRpcDto>) data.get("order");
        if(orderRpcDtos != null && orderRpcDtos.size() > 0){
            for(OrderRpcDto orderRpcDto : orderRpcDtos){
                if(!orderRpcDto.getOrderStatus().equals(BmsPortOrderLogServiceImpl.ORDER_STATUS_CAN_PAY)){
                    return ResultMapHelper.result(ResultCode.CODE_ERROR_100,BmsPortOrderLogServiceImpl.resultMsg.get(orderRpcDto.getOrderStatus()).toString());
                }
            }
        }
        BmsPortOrderLog bmsPortOrderLog = (BmsPortOrderLog) data.get("myDbOrder");

        Double wxPayTotal = ArithUtil.round(ArithUtil.mul(bmsPortOrderLog.getPayTotal(),100),0);
        String wxPayFree = String.valueOf(wxPayTotal.intValue());
        //wxPayFree = "10";
        if (openId == null) {
            openId = "11111111";
        }
        String ip = IpKit.getRealIp(RequestParamUtils.getRequest());
        if (StrUtil.isEmpty(ip)) {
            ip = "127.0.0.1";
        }

        WxPayApiConfig wxPayApiConfig = getApiConfig(WxPayBeanFactory.PUBLIC_APP_CHANNEL);

        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(wxPayApiConfig.getAppId())
                .mch_id(wxPayApiConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .body("口岸巴士")
                .attach("口岸巴士")
                .out_trade_no(bmsPortOrderLog.getOrderNo())
                .total_fee(wxPayFree)
                .spbill_create_ip(ip)
                .notify_url(wxPayApiConfig.getDomain().concat("/portBus/payNotify"))
                .trade_type(TradeType.JSAPI.getTradeType())
                .openid(openId)
                .build()
                .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);

        String xmlResult = WxPayApi.pushOrder(false, params);
        log.info(xmlResult);

        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
        String returnCode = result.get("return_code");
        String returnMsg = result.get("return_msg");
        String resultCode = result.get("result_code");
        if (!(WxPayKit.codeIsOk(returnCode) && "SUCCESS".equals(resultCode))) {
            return ResultMapHelper.result(ResultCode.CODE_ERROR_100,result.get("err_code_des"));
        }
        String prepayId = result.get("prepay_id");
        Map<String, String> packageParams = WxPayKit.miniAppPrepayIdCreateSign(wxPayApiConfig.getAppId(), prepayId,
                wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
        String jsonStr = JSON.toJSONString(packageParams);
        log.info("微信公众号支付的参数:" + jsonStr);
        Map<String,Object> resultMap = new HashMap<>();
        //resultMap.put("prepayId",prepayId);
        resultMap.putAll(packageParams);
        return ResultMapHelper.success(resultMap,ResultMsg.MSG_GET_SUCCESS);
    }*/


    /**
     * 获取RSA加密公钥
     */
    /*@RequestMapping(value = "/getPublicKey", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String getPublicKey() {
        try {
            WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();

            Map<String, String> params = new HashMap<String, String>(4);
            params.put("mch_id", wxPayApiConfig.getMchId());
            params.put("nonce_str", String.valueOf(System.currentTimeMillis()));
            params.put("sign_type", "MD5");
            String createSign = WxPayKit.createSign(params, wxPayApiConfig.getPartnerKey(), SignType.MD5);
            params.put("sign", createSign);
            return WxPayApi.getPublicKey(params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
        } catch (Exception e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }*/



    /**
     * 微信退款
     */
    //@PostMapping(value = "/refundOrder")
    //@ResponseBody
    //@CheckParams(checkAuth = true,params = {"orderId","groupBuyUseIds"})
    public Map<String,Object> refund(@RequestBody ParamsMap paramsMap) {
        Integer orderId = paramsMap.getInteger("orderId");
        BmsDxOrder bmsDxOrder = bmsDxOrderService.getBaseDao().findByIdAndIsDelete(orderId, Constants.COMMON_FLAG_FALSE_INT);
        if(bmsDxOrder == null){
            return ResultMapHelper.result(ResultCode.CODE_ORDER_REFUND_TOO_LOGN,"退款超时,请重试");
        }
        Map<String,Object> userDataMap = new HashMap<>();
        try {
            if(bmsDxOrder.getCreateWay() == null){
                bmsDxOrder.setCreateWay(Constants.ANDROID_CLIENT);
            }
            if(bmsDxOrder.getCreateWay() == Constants.WECHAT_MINAPP){
                WxPayApiConfig wxPayApiConfig = getApiConfig(WxPayBeanFactory.MIN_APP_CHANNEL);
                userDataMap = wxPayService.refund(wxPayApiConfig,refundNotifyUrl,paramsMap);
            }else if(bmsDxOrder.getCreateWay() == Constants.ANDROID_CLIENT){
                userDataMap = aliPayController.refundOrder(paramsMap);
            }
        }catch (Exception e){
            log.info(e.toString());
            userDataMap = ResultMapHelper.result(ResultCode.CODE_ORDER_REFUND_TOO_LOGN,"退款超时,请重试");
        }finally {
            return userDataMap;
        }
    }


//    @PostMapping(value = "/refundOrder1")
//    @ResponseBody
//    public Map<String,Object> refundOrder1(@RequestBody ParamsMap paramsMap) {
//        WxPayApiConfig wxPayApiConfig = getApiConfig(WxPayBeanFactory.MIN_APP_CHANNEL);
//        Map<String, String> params = RefundModel.builder()
//                .appid(wxPayApiConfig.getAppId())
//                .mch_id(wxPayApiConfig.getMchId())
//                .nonce_str(WxPayKit.generateStr())
//                .out_trade_no(paramsMap.getString("orderNo"))
//                .out_refund_no(WxPayKit.generateStr())
//                .total_fee(paramsMap.getString("refundMoney"))
//                .refund_fee(paramsMap.getString("refundMoney"))
//                .notify_url(notifyUrl)
//                .build()
//                .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5);
//        String xmlResult = WxPayApi.orderRefund(false, params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());
//        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
//        log.info("退款结果：" + JSON.toJSONString(result));
//
//        return null;
//    }


//    @PostMapping(value = "/refundOrderAli")
//    @ResponseBody
//    public Map<String,Object> refundOrderAli(@RequestBody ParamsMap paramsMap) {
//        String requestNo = AliPayUtil.getRequestNo();
//        Map<String,Object> b1 = new HashMap<>();
//        b1.put("out_trade_no",paramsMap.getString("orderNo"));
//        b1.put("refund_amount",paramsMap.getString("orderRefund"));
//        b1.put("refund_reason","正常退款");
//        b1.put("out_request_no", requestNo);
//        Integer old = paramsMap.getInteger("old");
//        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
//        request.setBizContent(JSON.toJSONString(b1));
//        AlipayTradeRefundResponse response = null;
//        try {
//            AlipayClient alipayClient = aliPayService.getAlipayClient();
//            if(old == 1){
//                Integer nowTime = DateTimeUtils.converDateToInterger(DateTimeUtils.converStringToDate("2019-02-13 20:30:00",DateTimeUtils.DATE_PATTERN_TIMESTAMP));
//                alipayClient = aliPayService.getAlipayClient(nowTime);
//            }
//            response = alipayClient.execute(request);
//            log.info("aliPay refund result：" + JSON.toJSONString(response));
//        } catch (AlipayApiException e) {
//            log.error("ali refund error : ",e);
//        }
//        return  null;
//    }

//    @PostMapping(value = "/refundOrder2")
//    @ResponseBody
//    public Map<String,Object> refundOrder2(@RequestBody ParamsMap paramsMap) {
//        WxPayApiConfig wxPayApiConfig = getApiConfig(WxPayBeanFactory.MIN_APP_CHANNEL);
//        Map<String,String> params = RefundQueryModel.builder()
//                .appid(wxPayApiConfig.getAppId())
//                .mch_id(wxPayApiConfig.getMchId())
//                .refund_id(paramsMap.getString("refundId"))
//                .nonce_str(WxPayKit.generateStr())
//                .build()
//                .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5, false);
//        String xmlResult = WxPayApi.orderRefundQuery(false, params);
//        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);
//        log.info("退款结果：" + JSON.toJSONString(result));
//        return null;
//    }



    /**
     * 微信退款查询
     */
    /*@RequestMapping(value = "/refundQuery", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String refundQuery(@RequestParam("transactionId") String transactionId,
                              @RequestParam("out_trade_no") String outTradeNo,
                              @RequestParam("out_refund_no") String outRefundNo,
                              @RequestParam("refund_id") String refundId) {

        WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();

        Map<String, String> params = RefundQueryModel.builder()
                .appid(wxPayApiConfig.getAppId())
                .mch_id(wxPayApiConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .transaction_id(transactionId)
                .out_trade_no(outTradeNo)
                .out_refund_no(outRefundNo)
                .refund_id(refundId)
                .build()
                .createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5);

        return WxPayApi.orderRefundQuery(false, params);
    }*/

    /**
     * 退款通知
     */
    @RequestMapping(value = "/refundNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String refundNotify(HttpServletRequest request) {
        try {
            String xmlMsg = HttpKit.readData(request);
            log.info("退款通知=" + xmlMsg);
            Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

            String returnCode = params.get("return_code");
            // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
            if (WxPayKit.codeIsOk(returnCode)) {
                String reqInfo = params.get("req_info");
                String decryptData = WxPayKit.decryptData(reqInfo,getApiConfig(WxPayBeanFactory.MIN_APP_CHANNEL).getPartnerKey());
                log.info("退款通知解密后的数据=" + decryptData);
                // 更新订单信息
                Map<String, String> refundData = WxPayKit.xmlToMap(decryptData);
                log.info("退款订单信息：" + JSON.toJSONString(refundData));
                // 发送通知等
                Map<String, String> xml = new HashMap<String, String>(2);
                xml.put("return_code", "SUCCESS");
                xml.put("return_msg", "OK");
                return WxPayKit.toXml(xml);
            }
        }catch (Exception e){}
        return null;
    }

    /**
     * 异步通知
     */
    @RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String payNotify() {
        HttpServletRequest request = RequestParamUtils.getRequest();
        String xmlMsg = HttpKit.readData(request);
        log.info("支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
        log.info("支付通知json格式：" + JSON.toJSONString(params));
        String returnCode = params.get("return_code");

        // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
        // 注意此处签名方式需与统一下单的签名类型一致
        if (WxPayKit.verifyNotify(params, getApiConfig(WxPayBeanFactory.MIN_APP_CHANNEL).getPartnerKey(), SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode) && "SUCCESS".equals(params.get("result_code"))) {
                // 更新订单信息
                wxPayService.payNotify(params);
                // 发送通知等
                Map<String, String> xml = new HashMap<String, String>(2);
                xml.put("return_code", "SUCCESS");
                xml.put("return_msg", "OK");
                return WxPayKit.toXml(xml);
            }
        }
        return null;
    }

    /**
     * 支付结果回调
     */
    @PostMapping("/appPayServicePayNotify")
    public synchronized void microServicePayNotify() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
        try{
            wxPayService.appPayServicePayNotify(request,response);
        }catch (Exception e){
            log.error("appPayServicePayNotify error",e);
        }
    }
}
